package br.com.ufpr.sgp.components;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField;
import org.apache.wicket.markup.html.form.HiddenField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.util.convert.ConversionException;
import org.apache.wicket.util.convert.IConverter;

import br.com.sebrae.pr.sgp.entities.base.BasePersistente;
import br.com.sebrae.pr.sgp.util.CustomStringUtils;
import br.com.sebrae.pr.sgp.util.IAutocompletable;
import br.com.sebrae.pr.sgp.util.exceptions.TratadorDeExcecoes;
import br.com.ufpr.util.base.BasePage;

public class CustomAutocompletePanel<T extends BasePersistente> extends Panel {
	private static final long serialVersionUID = 4561936960569449447L;

	private String hiddenIdValue = null;
	private final HiddenField<String> idField;
	private IModel<T> selected = new Model<T>();

	private final AutoCompleteTextField<T> autoCompleteTextField;

	public CustomAutocompletePanel(final String id, final IModel<T> model, final Class<T> type, final IAutocompletable<T> autocompletable) {
		this(id, model, type, autocompletable, false);
	}

	public CustomAutocompletePanel(final String id, final IModel<T> model, final Class<T> type, final IAutocompletable<T> autocompletable,
	        final boolean autofocus) {
		super(id);
		setRenderBodyOnly(true);
		this.idField = new HiddenField<String>("ac_hidden", new PropertyModel<String>(this, "hiddenIdValue"));
		idField.setOutputMarkupId(true);
		idField.setOutputMarkupPlaceholderTag(true);
		if (BasePage.alteracao(model)) {
			this.selected.setObject(model.getObject());
			final String idFieldValue = autocompletable.getChoiceId(model.getObject());
			if (CustomStringUtils.isNotBlank(idFieldValue)) {
				setHiddenIdValue(idFieldValue);
			}
		}
		add(idField);

		autoCompleteTextField = new AutoCompleteTextField<T>("ac_ac", model, type, new CustomAbstractAutoCompleteRenderer<T>(
		        autocompletable, idField) {
			private static final long serialVersionUID = -2889387886962047390L;

			@Override
			public boolean removeHtmlTags() {
				return CustomAutocompletePanel.this.removeHtmlTags();
			}
		}, new AutoCompleteSettings().setPreselect(true)) {
			private static final long serialVersionUID = 2639595364974472368L;

			@Override
			protected Iterator<T> getChoices(String input) {
				if (CustomStringUtils.isNotBlank(input)) {
					try {
						return autocompletable.pesquisarAutocomplete(input).iterator();

					} catch (Exception e) {
						TratadorDeExcecoes.logaException("Erro na pesquisa do autocomplete...", e);
					}
				}
				return new ArrayList<T>().iterator();
			}

			@SuppressWarnings("unchecked")
			@Override
			public <C> IConverter<C> getConverter(final Class<C> type) {
				final Class<T> fcType = getType();
				if (fcType != null && fcType.isAssignableFrom(type)) {
					return (IConverter<C>) new IConverter<T>() {
						private static final long serialVersionUID = -921372293571026889L;

						@Override
						public T convertToObject(String value, Locale locale) throws ConversionException {
							return autocompletable.getById(idField.getConvertedInput());
						}

						@Override
						public String convertToString(T value, Locale locale) {
							return autocompletable.getText(value);
						}
					};
				} else {
					return super.getConverter(type);
				}
			}
		};
		if (autofocus) {
			autoCompleteTextField.add(new AttributeAppender("autofocus", ""));
		}
		autoCompleteTextField.setOutputMarkupId(true);
		add(autoCompleteTextField);

		autoCompleteTextField.add(new OnChangeAjaxBehavior() {
			private static final long serialVersionUID = 4390746893060541214L;

			@Override
			protected void onUpdate(AjaxRequestTarget target) {
				if (CustomStringUtils.isNotBlank(getHiddenIdValue())) {
					// Existe um objeto no model
					if (CustomStringUtils.isBlank(autoCompleteTextField.getInput())
					        || !autoCompleteTextField.getInput().equals(
					                autocompletable.getText(autocompletable.getById(getHiddenIdValue())))) {
						// O campo autocomplete esta nulo ou o texto cadastrado nele e diferente do getText
						setHiddenIdValue(null);
						model.setObject(null);
						CustomAutocompletePanel.this.selected.setObject(null);
						onOptionSelected(target, CustomAutocompletePanel.this.selected);
						autoCompleteTextField.setDefaultModelObject(null);
						target.add(autoCompleteTextField);

					} else {
						final T t = autocompletable.getById(getHiddenIdValue());
						model.setObject(t);
						CustomAutocompletePanel.this.selected.setObject(t);
//						onOptionSelected(target, new PersistentDetachableModel<T>(autocompletable, t));

					}
				}
			}
		});

		idField.add(new OnChangeAjaxBehavior() {
			private static final long serialVersionUID = 2345534354787245528L;

			@Override
			protected void onUpdate(final AjaxRequestTarget target) {

				if (CustomStringUtils.isNotBlank(getHiddenIdValue())) {

					final T t = autocompletable.getById(getHiddenIdValue());
					model.setObject(t);
					CustomAutocompletePanel.this.selected.setObject(t);
//					onOptionSelected(target, new PersistentDetachableModel<T>(autocompletable, t));

				} else {
					CustomAutocompletePanel.this.selected.setObject(null);
					onOptionSelected(target, CustomAutocompletePanel.this.selected);

				}

			}

		});
	}

	protected long getLimiteRegistros() {
		return 20l;
	}

	public void onOptionSelected(final AjaxRequestTarget target, final IModel<T> objModel) {
	}

	public String getHiddenIdValue() {
		return hiddenIdValue;
	}

	public void setHiddenIdValue(String hiddenIdValue) {
		this.hiddenIdValue = hiddenIdValue;
	}

	public HiddenField<String> getHiddenField() {
		return idField;
	}

	public AutoCompleteTextField<T> getAutoCompleteTextField() {
		return autoCompleteTextField;
	}

	public IModel<T> getSelected() {
		return selected;
	}

	public boolean removeHtmlTags() {
		return true;
	}

}
